const router = require('koa-router')();
const NetworkScanner = require('network-scanner-js')
const {Transform} = require("stream");
const EventEmitter = require("events");
const Traceroute = require('nodejs-traceroute')

class SSEStream extends Transform {
  constructor() {
    super({
      writableObjectMode: true,
    });
  }

  _transform(data, _encoding, done) {
    this.push(`data: ${JSON.stringify(data)}\n\n`);
    done();
  }
}


// const events = new EventEmitter();
// events.setMaxListeners(0);

function getRange(range) {
  if (range.includes('-') === false) throw new Error('Invalid IP Range, e.g(192.168.1.1-254)');
  if (!range) throw new Error('IP Range cannot be null, e.g(192.168.1.1-254)');
  var array = [];
  var network = range.split('-')[0];
  var max = range.split('-')[1];
  if (max > 255) throw new Error('Invalid IP Range, e.g(192.168.1.1-254)');
  var min = network.split('.')[3];
  //network = network.replace(min, '');
  network = network.split('.')[0] + '.' + network.split('.')[1] + '.' + network.split('.')[2] + '.'
  for (var i = min; i <= max; i++) {
    var node = network.concat(i);
    array.push(node);
  }
  return array;
};

async function ipScan(range, cb) {
  const arr = getRange(range)

  await Promise.all(arr.map(async (a) => {
    try {
      const each_node = await new NetworkScanner().poll(a)

      each_node.status === 'online' ? (cb(each_node)) : (null)
    } catch (err) {
      throw new Error(err)
    }
  }))
  cb('end')
}

// const interval = setInterval(() => {
//   events.emit("data", { timestamp: new Date() });
// }, 1000);
//

router.post('/', async (ctx) => {

  //ping
  // if (ctx.request.body.tyspes == "ping") {
  //   let ping = require('child_process').spawn('ping', [ctx.request.body.ip]);
  //   let iconv = require('iconv-lite');
  //   var all = ""
  //   //  var logname = __dirname + '/' + 'log.txt';
  //   ping.stdout.on('data', data => {
  //     // fs.writeFileSync(logname, iconv.decode(data, 'cp936'))
  //     // let info = fs.readFileSync(logname, 'utf8')
  //     all += iconv.decode(data, 'cp936')
  //     // res.send(info)
  //     //  console.log(info)
  //   })
  //   ping.stderr.on('data', data => {
  //     // console.log(data);
  //   })
  //   //var ctx2 = ctx
  //   //  ping.on('close', code => {
  //   //       //console.log('data:', all);
  //   //       console.log(ctx);
  //   //       //res.send(all)
  //   //     ctx.body=all
  //   //   })
  //   function fping() {
  //     return new Promise(function (resolve, reject) {
  //       ping.on('close', code => {
  //         //console.log('data:', all);
  //         //   console.log(ctx);
  //         //   //res.send(all)
  //         // ctx.body=all
  //         resolve()
  //       })
  //     })
  //   }
  //
  //   await fping().then(() => {
  //       ctx.body = all
  //     }
  //   )
  // }
  // ;
  //
  // if (ctx.request.body.tyspes == "traceroute") {
  //   //toraceroute
  //   const Traceroute = require('nodejs-traceroute');
  //   var all2 = ""
  //   const tracer = new Traceroute();
  //   tracer
  //     .on('pid', (pid) => {
  //       all2 += `pid: ${pid} \n`;
  //     })
  //     .on('destination', (destination) => {
  //       all2 += `destination: ${destination} \n`;
  //     })
  //     .on('hop', (hop) => {
  //       all2 += `hop: ${JSON.stringify(hop)} \n`;
  //     })
  //     // .on('close', (code) => {
  //     //   all2 += `close: code ${code}`;
  //     //   //res.send(all2)
  //     //   ctx.response.body = all
  //     // });
  //
  //   tracer.trace(ctx.request.body.ip);
  //
  //   function fping() {
  //     return new Promise(function (resolve, reject) {
  //       tracer.on('close', code => {
  //         all2 += `close: code ${code}`;
  //         resolve(all2)
  //       })
  //     })
  //   }
  //
  //   await fping().then((data) => {
  //      // all2 += `close: code ${code}`;
  //       //res.send(all2)
  //       ctx.response.body = data
  //   })
  //
  // }

  const netScan = new NetworkScanner()
  const config = {
    repeat: 4, //Specifies how many pings to send to the host, if null default is 1
    size: 56, //Size of bytes in each packet sent, if null default is 32
    timeout: 1 //Specifies the timeout of each ping in seconds, if null default is 1
  }
  try {
    if (ctx.request.body.type == "ping") {
      await netScan.poll(ctx.request.body.ip, config).then((res) => {
        ctx.response.body = res
      })
    }
    if (ctx.request.body.type == "tcp") {
      const {ping} = require("tcp-ping-node")
      const options = {host: ctx.request.body.ip, port: ctx.request.body.tcp, timeout: 10000}
      const result = await ping(options);
      ctx.response.body = result

    }
  } catch (e) {
    ctx.response.status = 400
    ctx.response.body = e
  }

  if (ctx.request.body.type == "netPing") {
    //console.log(ctx.request.body)
    var array = [];
    try {
      await ipScan(ctx.request.body.network, host => {
        if (host != 'end') {
          array.push(host)
        } else {
          ctx.response.body = array
        }
      })
    } catch (e) {
      ctx.response.body = e
    }
  }

  //采用SSE技术长连接
  if (ctx.request.body.type == "traceroute") {
    function traceroute(dest, cb) {
      try {
        const tracer = new Traceroute();
        tracer.on('hop', (hop) => {
          console.log(hop)
          cb(hop)
        }).on('close', (code) => {
          cb('end')
          return
        })
        tracer.trace(dest);
      } catch (ex) {
        return ex
      }
    }

    ctx.request.socket.setTimeout(0);
    ctx.req.socket.setNoDelay(true);
    ctx.req.socket.setKeepAlive(true);
    ctx.set({
      "Content-Type": "text/event-stream",
      "Cache-Control": "no-cache",
      "Connection": "keep-alive",
    })
    //stream是服务器与浏览器之间的流
    const stream = new SSEStream();
    ctx.status = 200;
    traceroute(ctx.request.body.ip, data => {
      if (data = 'end') {
        stream.write(`close: end\n\n`);
      } else {
        stream.write(`data: ${JSON.stringify(data)}\n\n`);
      }

    })
    const listener = (data) => {
      stream.write(data);
    };
    events.on("data", listener);
    stream.on("close", () => {
      console.log("关闭流")
      //clearInterval(interval);
      events.off("data", listener);
    });
    ctx.body = stream;
  }

});

router.get('/', (ctx) => {
  let tracer = null
  let tracerpid =  null
  let isKilled = false
  function traceroute(dest, cb) {
    try {
      tracer = new Traceroute();
      tracer.on('hop', (hop) => {
        console.log("hop中。。。。。")
        cb(hop)
      }).on('close', (code) => {
        if(code==0){
          //traceroute已完成 来自tracer的消息
        console.log("来自tracer的close消息")
        isKilled = true
        //给客户端发个消息
        cb('end')
        }
        if(code==99){
         console.log("来自客户端的的close消息")
         if(!isKilled)  process.kill(tracerpid)
        }
        return
      }).on('pid', (pid) => {
            console.log(`pid: ${pid}`);
            tracerpid = pid
        })
      tracer.trace(dest);
    } catch (ex) {
      return ex
    }
  }

  ctx.request.socket.setTimeout(0);
  ctx.req.socket.setNoDelay(true);
  ctx.req.socket.setKeepAlive(true);
  ctx.set({
    "Content-Type": "text/event-stream",
    "Cache-Control": "no-cache",
    "Connection": "keep-alive",
  })
  //stream是服务器与浏览器之间的流
  const stream = new SSEStream();
  ctx.status = 200;

  traceroute(ctx.request.query.ip, data => {
    if (!stream.destroyed) {
      if (data == 'end') {
        stream.write(`close: end`);
      } else {
        stream.write(`${JSON.stringify(data)}`);
      }
    }else {
      return
    }


  });


  const listener = (data) => {
    stream.write(data);
  };
  //如果事件on类型为data
  //events.on("data", listener);
  //此close消息来自客户端
  stream.on("close", () => {
    console.log("关闭流")
    tracer.emit('close',99)
    // events.off("data", listener);
  });
  ctx.body = stream;


  // ctx.request.socket.setTimeout(0);
  // ctx.req.socket.setNoDelay(true);
  // ctx.req.socket.setKeepAlive(true);
  // ctx.set({
  //   "Content-Type": "text/event-stream",
  //   "Cache-Control": "no-cache",
  //   "Connection": "keep-alive",
  // })
  // const stream = new SSEStream();
  // ctx.status = 200;
  //
  // // const interval = setInterval(() => {
  // //   stream.write(`data: ${new Date()}\n\n`);
  // // }, 1000);
  // const netScan = new NetworkScanner()
  // netScan.ipScan('192.168.1.1-254', host => {
  //   stream.write(`data: ${JSON.stringify(host)}\n\n`);
  // })
  //
  // const listener = (data) => {
  //   stream.write(data);
  // };
  // events.on("data", listener);
  // stream.on("close", () => {
  //   console.log("关闭流")
  //   //clearInterval(interval);
  //   events.off("data", listener);
  // });
  // ctx.body = stream;
  // //ctx.response.body = "123213131231"
})

module.exports = router;
